package nmrworkflow.framework.workflows.base;

import java.io.IOException;
import java.util.Iterator;
import java.util.Vector;

import nmrworkflow.framework.beans.datasets.NmrDataSet;
import nmrworkflow.framework.configuration.Preferences;
import nmrworkflow.framework.executionmodule.ExecutionQueue;
import nmrworkflow.framework.functionwrappers.FunctionWrapper;

/**
 * Base class for all workflows.  Should be extended when creating
 * a new workflow.
 * @author rjn
 *
 */
public abstract class Workflow {
	
	protected WorkflowBean bean;
	
	/**
	 * A unique identifier for the workflow.  Preferably something
	 * descriptive.
	 */
	final protected String name;
	
	/**
	 * Instantiated when NMRWorkflow is run.
	 */
	public Workflow(String name) {
		this.name = name;
	}

	/**
	 * Called when the user clicks "Configure" on the main view.
	 * Should pop up a GUI and set the appropriate values in the
	 * WorkflowBean.
	 * @param input
	 */
	public abstract void configure(NmrDataSet input);
	
	/**
	 * Converts the information in the WorkflowBean to
	 * functions which are used to create scripts for 
	 * the various tools.
	 * @return
	 */
	protected abstract Vector<FunctionWrapper> buildFunctionWrappers();
	
	/**
	 * Returns Executors which can then be run.
	 * @param in
	 * @param out
	 * @return
	 * @throws IOException
	 */
	public ExecutionQueue getExecutors() throws IOException, Exception {
		Preferences cb = Preferences.getInstance();
		ExecutionQueue executors = new ExecutionQueue();
		Vector<FunctionWrapper> functions = this.buildFunctionWrappers();
		
		// a workflow should always return FunctionWrapper's
		if(functions == null)
			throw new Exception();
		
		Iterator<FunctionWrapper> iter = functions.iterator();
		
		while(iter.hasNext())
			executors.enqueue( iter.next().getExecutable() );

		return executors;
		
	}
	
	/**
	 * Should create a new instance of the bean.  As workflows are only instantiated once,
	 * this it allows the workflow to completely reset it's state.  Called whenever the user
	 * changes workflows.
	 */
	public abstract void reset();

	public WorkflowBean getBean() {
		return bean;
	}

	public void setBean(WorkflowBean bean) {
		this.bean = bean;
	}

	public String getName() {
		return name;
	}
}
